package handler

import (
	"net/http"

	"database/sql"

	"gitee.com/hp-huiw/family-expense-api/internal/constant"
	"gitee.com/hp-huiw/family-expense-api/internal/dto"
	"gitee.com/hp-huiw/family-expense-api/internal/service"
	"github.com/gin-gonic/gin"
)

type IncomeExpenseDetailTypeHandler interface {
	QueryByAccountGroup(ctx *gin.Context)
	CheckExisting(ctx *gin.Context)
	QueryAnalysisNotIncludedDetailTypes(ctx *gin.Context)
	ResetOrder(ctx *gin.Context)
	Add(ctx *gin.Context)
	Update(ctx *gin.Context)
	Delete(ctx *gin.Context)
	BatchDelete(ctx *gin.Context)
}

func NewIncomeExpenseDetailTypeHandler(db *sql.DB) IncomeExpenseDetailTypeHandler {
	return &incomeExpenseDetailTypeHandler{
		incomeExpenseDetailTypeService: service.NewIncomeExpenseDetailTypeService(db),
	}
}

// Matches /query-by-account-group of http get action.
func (h *incomeExpenseDetailTypeHandler) QueryByAccountGroup(ctx *gin.Context) {
	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	incomeExpenseType := ctx.Query("incomeExpenseType")
	result, err := h.incomeExpenseDetailTypeService.Query(c, accountGroupID, incomeExpenseType)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /check-existing of http get action.
func (h *incomeExpenseDetailTypeHandler) CheckExisting(ctx *gin.Context) {
	c := ctx.Request.Context()
	incomeExpenseType := ctx.Query("incomeExpenseType")
	id := ctx.Query("id")
	name := ctx.Query("name")
	accountGroupID := GetClaims(ctx).AccountGroupID
	result, err := h.incomeExpenseDetailTypeService.ExistsBy(c, accountGroupID, incomeExpenseType, id, name)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /query-analysis-not-included-detail-types of http get action.
func (h *incomeExpenseDetailTypeHandler) QueryAnalysisNotIncludedDetailTypes(ctx *gin.Context) {
	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	incomeDetailTypes, err := h.incomeExpenseDetailTypeService.QueryAnalysisNotIncludedDetailTypes(c, accountGroupID, constant.IncomeExpenseTypeIncome)

	if err != nil {
		ctx.Error(err)
		return
	}

	expenseDetailTypes, err := h.incomeExpenseDetailTypeService.QueryAnalysisNotIncludedDetailTypes(c, accountGroupID, constant.IncomeExpenseTypeExpense)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, map[string]any{
		"incomeDetailTypes":  incomeDetailTypes,
		"expenseDetailTypes": expenseDetailTypes,
	})
}

// Matches /reset-order of http post action.
func (h *incomeExpenseDetailTypeHandler) ResetOrder(ctx *gin.Context) {
	var postedData struct {
		DetailTypeIDs []string `json:"detailTypeIDs"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	err := h.incomeExpenseDetailTypeService.ResetOrder(c, accountGroupID, postedData.DetailTypeIDs)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendStatusResponse(ctx, http.StatusNoContent)
}

// Matches /add of http post action.
func (h *incomeExpenseDetailTypeHandler) Add(ctx *gin.Context) {
	postedData := &dto.IncomeExpenseDetailTypeRequest{}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	result, err := h.incomeExpenseDetailTypeService.Add(c, postedData, accountGroupID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /update of http post action.
func (h *incomeExpenseDetailTypeHandler) Update(ctx *gin.Context) {
	postedData := &dto.IncomeExpenseDetailTypeRequest{}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	result, err := h.incomeExpenseDetailTypeService.Update(c, postedData, accountGroupID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /delete of http post action.
func (h *incomeExpenseDetailTypeHandler) Delete(ctx *gin.Context) {
	var postedData struct {
		IncomeExpenseType string `json:"incomeExpenseType"`
		Name              string `json:"name"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	result, err := h.incomeExpenseDetailTypeService.Delete(c, postedData.IncomeExpenseType, postedData.Name, accountGroupID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Matches /batch-delete of http post action.
func (h *incomeExpenseDetailTypeHandler) BatchDelete(ctx *gin.Context) {
	var postedData struct {
		IncomeExpenseType string   `json:"incomeExpenseType"`
		Names             []string `json:"names"`
	}

	if err := ctx.ShouldBindJSON(&postedData); err != nil {
		ctx.Error(err)
		return
	}

	c := ctx.Request.Context()
	accountGroupID := GetClaims(ctx).AccountGroupID
	result, err := h.incomeExpenseDetailTypeService.BatchDelete(c, postedData.IncomeExpenseType, postedData.Names, accountGroupID)

	if err != nil {
		ctx.Error(err)
		return
	}

	SendDataResponse(ctx, result)
}

// Container of IncomeExpenseDetailTypeHandler functions.
type incomeExpenseDetailTypeHandler struct {
	incomeExpenseDetailTypeService service.IncomeExpenseDetailTypeService
}
